import fs from "fs";
import path from "path";
import * as remote from '@electron/remote';
import { debounce, throttle } from "lodash";

import { SimulateController } from "./Controller";
import { InfoLevel, LogRecord } from "./_";

const logsDir = remote.app.getPath('logs');
const dirPath = path.join(logsDir, 'm-simulate');

const FLUSH_LOG_TIMEOUT = 200;

export class LogFileService {

  indexPath = '';
  [InfoLevel.DEBUG] = '';
  [InfoLevel.INFO] = '';
  [InfoLevel.WARN] = '';
  [InfoLevel.ERROR] = '';

  flushCache: LogRecord[] = [];

  constructor(public controller: SimulateController) {
  }

  serviceInit() {
    this.indexPath = path.join(dirPath, 'index.log');
    this[InfoLevel.DEBUG] = path.join(dirPath, 'debug.log');
    this[InfoLevel.INFO] = path.join(dirPath, 'info.log');
    this[InfoLevel.WARN] = path.join(dirPath, 'warn.log');
    this[InfoLevel.ERROR] = path.join(dirPath, 'error.log');

    this.clear();
  }

  clear() {
    if (fs.existsSync(dirPath)) {
      fs.rmSync(dirPath, { recursive: true });
      if (!fs.existsSync(dirPath)) {
        fs.mkdirSync(dirPath);
      }
    } else {
      fs.mkdirSync(dirPath);
    }
  }

  private writeLog(logs: LogRecord[]) {
    let level: InfoLevel | undefined;
    let content = '';
    for (let i = 0; i < logs.length; i++) {
      const log = logs[i];
      if (!level) {
        level = log.level;
      }
      if (log.context) {
        content += log.time + ' : ' + log.context + '\n';
      }
    }
    if (level && content) {
      switch (level) {
        case InfoLevel.ERROR:
          fs.appendFileSync(this[InfoLevel.ERROR], content);
          break;
        case InfoLevel.WARN:
          fs.appendFileSync(this[InfoLevel.WARN], content);
          break;
        case InfoLevel.INFO:
          fs.appendFileSync(this[InfoLevel.INFO], content);
          break;
        case InfoLevel.DEBUG:
          fs.appendFileSync(this[InfoLevel.DEBUG], content);
          break;
      }
    }
  }

  private flushLogs = throttle(() => {
    if (this.flushCache.length > 0) {
      const errorLog: LogRecord[] = [];
      const warnLog: LogRecord[] = [];
      const infoLog: LogRecord[] = [];
      const debugLog: LogRecord[] = [];
      let content = '';
      for (let i = 0; i < this.flushCache.length; i++) {
        const it = this.flushCache[i];
        if (it.context) {
          if (it.level === InfoLevel.ERROR) {
            errorLog.push(it);
          } else if (it.level === InfoLevel.WARN) {
            warnLog.push(it);
          } else if (it.level === InfoLevel.INFO) {
            infoLog.push(it);
          } else if (it.level === InfoLevel.DEBUG) {
            debugLog.push(it);
          }
          content += it.time + ' : ' + it.context + '\n';
        }
      }
      // 写入总日志文件
      fs.appendFileSync(this.indexPath, content);
      this.writeLog(errorLog);
      this.writeLog(warnLog);
      this.writeLog(infoLog);
      this.writeLog(debugLog);
      this.flushCache = [];
    }
  }, FLUSH_LOG_TIMEOUT, { leading: true, trailing: true });

  appendLog = (log: LogRecord) => {
    this.flushCache.push(log);
    this.flushLogs();
  }

  /**
   * 根据日志级别获取日志文件路径
   */
  getLogFilePath(level: InfoLevel) {
    return this[level];
  }

  /**
   * 根据日志级别获取日志文件内容
   */
  getLogContent(level?: InfoLevel) {
    if (!level) {
      return fs.readFileSync(this.indexPath, 'utf-8');
    }
    return fs.readFileSync(this[level], 'utf-8');
  }

  /**
   * 拷贝日志文件到指定目录
   */
  copyLogsTo(targetDir: string) {
    fs.copyFileSync(this.indexPath, targetDir);
  }
}